home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / bash-1.12 / dist / unwind_prot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-04  |  6.9 KB  |  292 lines

  1. /* I can't stand it anymore!  Please can't we just write the
  2.    whole Unix system in lisp or something? */
  3.  
  4. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  5.  
  6. This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8. Bash is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 1, or (at your option) any later
  11. version.
  12.  
  13. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License along
  19. with Bash; see the file COPYING.  If not, write to the Free Software
  20. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. /* **************************************************************** */
  23. /*                                    */
  24. /*              Unwind Protection Scheme for Bash            */
  25. /*                                    */
  26. /* **************************************************************** */
  27. #include <signal.h>
  28. #include "config.h"
  29. #include "general.h"
  30. #include "unwind_prot.h"
  31.  
  32. /* If CLEANUP is null, then ARG contains a tag to throw back to. */
  33. typedef struct _uwp {
  34.   struct _uwp *next;
  35.   Function *cleanup;
  36.   char *arg;
  37. } UNWIND_ELT;
  38.  
  39. static void
  40.   unwind_frame_discard_internal (), unwind_frame_run_internal (),
  41.   add_unwind_protect_internal (), remove_unwind_protect_internal (),
  42.   run_unwind_protects_internal ();
  43.  
  44. static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
  45.  
  46. /* Run a function without interrupts. */
  47. void
  48. without_interrupts (function, arg1, arg2)
  49.      VFunction *function;
  50.      char *arg1, *arg2;
  51. {
  52. #if defined (_POSIX_VERSION)
  53.   sigset_t set, oset;
  54.  
  55.   sigemptyset (&set);
  56.   sigemptyset (&oset);
  57.  
  58.   sigaddset (&set, SIGINT);
  59.   sigprocmask (SIG_BLOCK, &set, &oset);
  60. #else
  61. #  if defined (USG)
  62.   SigHandler *old_int;
  63.  
  64.   old_int = (SigHandler *)signal (SIGINT, SIG_IGN);
  65. #  else
  66.   int oldmask = sigblock (SIGINT);
  67. #  endif
  68. #endif
  69.  
  70.   (*function)(arg1, arg2);
  71.  
  72. #if defined (_POSIX_VERSION)
  73.   sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  74. #else
  75. #  if defined (USG)
  76.   signal (SIGINT, old_int);
  77. #  else
  78.   sigsetmask (oldmask);
  79. #  endif
  80. #endif
  81. }
  82.  
  83. /* Start the beginning of a region. */
  84. void
  85. begin_unwind_frame (tag)
  86.      char *tag;
  87. {
  88.   add_unwind_protect ((Function *)NULL, tag);
  89. }
  90.  
  91. /* Discard the unwind protects back to TAG. */
  92. void
  93. discard_unwind_frame (tag)
  94.      char *tag;
  95. {
  96.   without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
  97. }
  98.  
  99. /* Run the unwind protects back to TAG. */
  100. void
  101. run_unwind_frame (tag)
  102.      char *tag;
  103. {
  104.   without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
  105. }
  106.  
  107. /* Add the function CLEANUP with ARG to the list of unwindable things. */
  108. void
  109. add_unwind_protect (cleanup, arg)
  110.      Function *cleanup;
  111.      char *arg;
  112. {
  113.   without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
  114. }
  115.  
  116. /* Remove the top unwind protect from the list. */
  117. void
  118. remove_unwind_protect ()
  119. {
  120.   without_interrupts
  121.     (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
  122. }
  123.  
  124. /* Run the list of cleanup functions in unwind_protect_list. */
  125. void
  126. run_unwind_protects ()
  127. {
  128.   without_interrupts
  129.     (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
  130. }
  131.  
  132. /* **************************************************************** */
  133. /*                                    */
  134. /*                        The Actual Functions                         */
  135. /*                                    */
  136. /* **************************************************************** */
  137.  
  138. static void
  139. add_unwind_protect_internal (cleanup, arg)
  140.      Function *cleanup;
  141.      char *arg;
  142. {
  143.   UNWIND_ELT *elt;
  144.  
  145.   elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
  146.   elt->cleanup = cleanup;
  147.   elt->arg = arg;
  148.   elt->next = unwind_protect_list;
  149.   unwind_protect_list = elt;
  150. }
  151.  
  152. static void
  153. remove_unwind_protect_internal ()
  154. {
  155.   UNWIND_ELT *elt = unwind_protect_list;
  156.  
  157.   if (elt)
  158.     {
  159.       unwind_protect_list = unwind_protect_list->next;
  160.       free (elt);
  161.     }
  162. }
  163.  
  164. static void
  165. run_unwind_protects_internal ()
  166. {
  167.   UNWIND_ELT *t, *elt = unwind_protect_list;
  168.  
  169.   while (elt)
  170.    {
  171.       /* This function can be run at strange times, like when unwinding
  172.     the entire world of unwind protects.  Thus, we may come across
  173.      an element which is simply a label for a catch frame.  Don't call
  174.      the non-existant function. */
  175.       if (elt->cleanup)
  176.     (*(elt->cleanup)) (elt->arg);
  177.  
  178.       t = elt;
  179.       elt = elt->next;
  180.       free (t);
  181.     }
  182.   unwind_protect_list = elt;
  183. }
  184.  
  185. static void
  186. unwind_frame_discard_internal (tag)
  187.      char *tag;
  188. {
  189.   UNWIND_ELT *elt;
  190.  
  191.   while (elt = unwind_protect_list)
  192.     {
  193.       unwind_protect_list = unwind_protect_list->next;
  194.       if (!elt->cleanup && (STREQ (elt->arg, tag)))
  195.     {
  196.       free (elt);
  197.       break;
  198.     }
  199.       else
  200.     free (elt);
  201.     }
  202. }
  203.  
  204. static void
  205. unwind_frame_run_internal (tag)
  206.      char *tag;
  207. {
  208.   UNWIND_ELT *elt;
  209.  
  210.   while (elt = unwind_protect_list)
  211.     {
  212.       unwind_protect_list = elt->next;
  213.  
  214.       /* If tag, then compare. */
  215.       if (!elt->cleanup)
  216.     {
  217.       if (strcmp (elt->arg, tag) == 0)
  218.         {
  219.           free (elt);
  220.           break;
  221.         }
  222.       free (elt);
  223.       continue;
  224.     }
  225.       else
  226.     {
  227.       (*(elt->cleanup)) (elt->arg);
  228.       free (elt);
  229.     }
  230.     }
  231. }
  232.  
  233. /* Structure describing a saved variable and the value to restore it to. */
  234. typedef struct {
  235.   int *variable;
  236.   char *desired_setting;
  237.   int size;
  238. } SAVED_VAR;
  239.  
  240. /* Restore the value of a variable, based on the contents of SV.  If
  241.    sv->size is greater than sizeof (char *), sv->desired_setting points to
  242.    a block of memory SIZE bytes long holding the value, rather than the
  243.    value itself.  This block of memory is copied back into the variable. */
  244. static void
  245. restore_variable (sv)
  246.      SAVED_VAR *sv;
  247. {
  248.  
  249.   /* I wrote this switch statement not realizing how silly some compilers
  250.      can be.  Since we expect both cases to be the same size, it really
  251.      makes no difference (today), but it irks me that I cannot express the
  252.      thought clearly. */
  253.   switch (sv->size)
  254.     {
  255.     /* case sizeof (char *): */
  256.     case sizeof (int):
  257.       *(sv->variable) = (int)sv->desired_setting;
  258.       break;
  259.  
  260.     default:
  261.       bcopy (sv->desired_setting, (char *)sv->variable, sv->size);
  262.       free (sv->desired_setting);
  263.     }
  264.  
  265.   free (sv);
  266. }
  267.  
  268. /* Save the value of a variable so it will be restored when unwind-protects
  269.    are run.  VAR is a pointer to the variable.  VALUE is the value to be
  270.    saved.  SIZE is the size in bytes of VALUE.  If SIZE is bigger than what
  271.    can be saved in a char *, memory will be allocated and the value saved
  272.    into that using bcopy (). */
  273. void
  274. unwind_protect_var (var, value, size)
  275.      int *var;
  276.      char *value;
  277.      int size;
  278. {
  279.   SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
  280.  
  281.   s->variable = var;
  282.   if (size > sizeof (char *))
  283.     {
  284.       s->desired_setting = (char *)xmalloc (size);
  285.       bcopy (value, s->desired_setting, size);
  286.     }
  287.   else
  288.     s->desired_setting = value;
  289.   s->size = size;
  290.   add_unwind_protect ((Function *)restore_variable, (char *)s);
  291. }
  292.